﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DatabaseExtension.Enums.Sql;

namespace DatabaseExtension.ConnectionString
{
    /// <summary>
    /// Provide connection information for SqlConnection
    /// <seealso cref="http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder%28v=vs.100%29.aspx"/>
    /// </summary>
    public class SqlConnectionInfo : ConnectionInfo
    {
        /// <summary>
        /// Direct access to the SqlConnectionStringBuilder using DbConnectionStringBuilder base.
        /// </summary>
        public System.Data.SqlClient.SqlConnectionStringBuilder SqlConnectionStringBuilder
        {
            get
            {
                return this.ConnectionStringBuilder as System.Data.SqlClient.SqlConnectionStringBuilder;
            }
        }
        #region ConnectionStringBuilder Derived Parameter
        /// <summary>
        /// Gets or sets the name of the application associated with the connection string.
        /// </summary>
        public String ApplicationName
        {
            get
            {
                return this.SqlConnectionStringBuilder.ApplicationName;
            }
            set
            {
                this.SqlConnectionStringBuilder.ApplicationName = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether asynchronous processing 
        /// is allowed by the connection created by using this connection string.
        /// </summary>
        public Boolean AsynchronousProcessing
        {
            get
            {
                return this.SqlConnectionStringBuilder.AsynchronousProcessing;
            }
            set
            {
                this.SqlConnectionStringBuilder.AsynchronousProcessing = value;
            }
        }
        /// <summary>
        /// Gets or sets a string that contains the name of the primary data file. This includes 
        /// the full path name of an attachable database.
        /// </summary>
        public String AttachDBFilename
        {
            get
            {
                return this.SqlConnectionStringBuilder.AttachDBFilename;
            }
            set
            {
                this.SqlConnectionStringBuilder.AttachDBFilename = value;
            }
        }
        /// <summary>
        /// Gets or sets the length of time (in seconds) to wait for a connection to the server
        /// before terminating the attempt and generating an error.
        /// </summary>
        public int ConnectTimeout
        {
            get
            {
                return this.SqlConnectionStringBuilder.ConnectTimeout;
            }
            set
            {
                this.SqlConnectionStringBuilder.ConnectTimeout = value;
            }
        }
        /// <summary>
        /// Gets or sets a value that indicates whether a client/server or in-process connection 
        /// to SQL Server should be made.
        /// </summary>
        public Boolean ContextConnection
        {
            get
            {
                return this.SqlConnectionStringBuilder.ContextConnection;
            }
            set
            {
                this.SqlConnectionStringBuilder.ContextConnection = value;
            }
        }
        /// <summary>
        /// Gets or sets the SQL Server Language record name.
        /// </summary>
        public System.Globalization.CultureInfo CurrentLanguage
        {
            get
            {
                String ci = this.SqlConnectionStringBuilder.CurrentLanguage;
                System.Globalization.CultureInfo result = String.IsNullOrEmpty(ci) ? System.Globalization.CultureInfo.InvariantCulture : new System.Globalization.CultureInfo(ci);
                return result;
            }
            set
            {
                this.SqlConnectionStringBuilder.CurrentLanguage = value.Name;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether SQL Server uses SSL encryption for 
        /// all data sent between the client and server if the server has a certificate installed.
        /// </summary>
        public Boolean Encrypt
        {
            get
            {
                return this.SqlConnectionStringBuilder.Encrypt;
            }
            set
            {
                this.SqlConnectionStringBuilder.Encrypt = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether the SQL Server connection
        /// pooler automatically enlists the connection in the creation thread's current transaction context.
        /// </summary>
        public Boolean Enlist
        {
            get
            {
                return this.SqlConnectionStringBuilder.Enlist;
            }
            set
            {
                this.SqlConnectionStringBuilder.Enlist = value;
            }
        }
        /// <summary>
        /// Gets or sets the name or address of the partner server to connect to if the primary 
        /// server is down.
        /// </summary>
        public String FailoverPartner
        {
            get
            {
                return this.SqlConnectionStringBuilder.FailoverPartner;
            }
            set
            {
                this.SqlConnectionStringBuilder.FailoverPartner = value;
            }
        }
        /// <summary>
        /// Gets or sets the name of the database associated with the connection.
        /// </summary>
        public String InitialCatalog
        {
            get
            {
                return this.SqlConnectionStringBuilder.InitialCatalog;
            }
            set
            {
                this.SqlConnectionStringBuilder.InitialCatalog = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether User ID and Password are 
        /// specified in the connection (when false) or whether the current Windows account 
        /// credentials are used for authentication (when true).
        /// </summary>
        public Boolean IntegratedSecurity
        {
            get
            {
                return this.SqlConnectionStringBuilder.IntegratedSecurity;
            }
            set
            {
                this.SqlConnectionStringBuilder.IntegratedSecurity = value;
            }
        }
        /// <summary>
        /// Gets or sets the minimum time, in seconds, for the connection to 
        /// live in the connection pool before being destroyed.
        /// </summary>
        public int LoadBalanceTimeout
        {
            get
            {
                return this.SqlConnectionStringBuilder.LoadBalanceTimeout;
            }
            set
            {
                this.SqlConnectionStringBuilder.LoadBalanceTimeout = value;
            }
        }
        /// <summary>
        /// Gets or sets the maximum number of connections allowed in the 
        /// connection pool for this specific connection string.
        /// </summary>
        public int MaxPoolSize
        {
            get
            {
                return this.SqlConnectionStringBuilder.MaxPoolSize;
            }
            set
            {
                this.SqlConnectionStringBuilder.MaxPoolSize = value;
            }
        }
        /// <summary>
        /// Gets or sets the minimum number of connections allowed 
        /// in the connection pool for this specific connection string.
        /// </summary>
        public int MinPoolSize
        {
            get
            {
                return this.SqlConnectionStringBuilder.MinPoolSize;
            }
            set
            {
                this.SqlConnectionStringBuilder.MinPoolSize = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether multiple 
        /// active result sets can be associated with the associated connection.
        /// </summary>
        public Boolean MultipleActiveResultSets
        {
            get
            {
                return this.SqlConnectionStringBuilder.MultipleActiveResultSets;
            }
            set
            {
                this.SqlConnectionStringBuilder.MultipleActiveResultSets = value;
            }
        }
        /// <summary>
        /// Gets or sets a string that contains the name of the network 
        /// library used to establish a connection to the SQL Server.
        /// </summary>
        public String NetworkLibrary
        {
            get
            {
                return this.SqlConnectionStringBuilder.NetworkLibrary;
            }
            set
            {
                this.SqlConnectionStringBuilder.NetworkLibrary = value;
            }
        }
        /// <summary>
        /// Gets or sets the size in bytes of the network packets
        /// used to communicate with an instance of SQL Server.
        /// </summary>
        public int PacketSize
        {
            get
            {
                return this.SqlConnectionStringBuilder.PacketSize;
            }
            set
            {
                this.SqlConnectionStringBuilder.PacketSize = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates if security-sensitive 
        /// information, such as the password, is not returned as part of the 
        /// connection if the connection is open or has ever been in an open state.
        /// </summary>
        public Boolean PersistSecurityInfo
        {
            get
            {
                return this.SqlConnectionStringBuilder.PersistSecurityInfo;
            }
            set
            {
                this.SqlConnectionStringBuilder.PersistSecurityInfo = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether the connection 
        /// will be pooled or explicitly opened every time that the connection is requested.
        /// </summary>
        public Boolean Pooling
        {
            get
            {
                return this.SqlConnectionStringBuilder.Pooling;
            }
            set
            {
                this.SqlConnectionStringBuilder.Pooling = value;
            }
        }
        /// <summary>
        /// Gets or sets a Boolean value that indicates whether 
        /// replication is supported using the connection.
        /// </summary>
        public Boolean Replication
        {
            get
            {
                return this.SqlConnectionStringBuilder.Replication;
            }
            set
            {
                this.SqlConnectionStringBuilder.Replication = value;
            }
        }
        /// <summary>
        /// Gets or sets a string value that indicates how the connection 
        /// maintains its association with an enlisted System.Transactions transaction.
        /// </summary>
        public SqlTransactionBinding TransactionBinding
        {
            get
            {
                return (SqlTransactionBinding)this.SqlConnectionStringBuilder.TransactionBinding.StringToEnum(typeof(SqlTransactionBinding));
            }
            set
            {
                this.SqlConnectionStringBuilder.TransactionBinding = value.EnumToString();
            }
        }
        /// <summary>
        /// Gets or sets a value that indicates whether the channel will be 
        /// encrypted while bypassing walking the certificate chain to validate trust.
        /// </summary>
        public Boolean TrustServerCertificate
        {
            get
            {
                return this.SqlConnectionStringBuilder.TrustServerCertificate;
            }
            set
            {
                this.SqlConnectionStringBuilder.TrustServerCertificate = value;
            }
        }
        /// <summary>
        /// Gets or sets a string value that indicates the type system the application expects.
        /// </summary>
        public SqlTypeSystemVersion TypeSystemVersion
        {
            get
            {
                return (SqlTypeSystemVersion)this.SqlConnectionStringBuilder.TypeSystemVersion.StringToEnum(typeof(SqlTypeSystemVersion));
            }
            set
            {
                this.SqlConnectionStringBuilder.TypeSystemVersion = value.EnumToString();
            }
        }
        /// <summary>
        /// Gets or sets a value that indicates whether to redirect the connection 
        /// from the default SQL Server Express instance to a runtime-initiated 
        /// instance running under the account of the caller.
        /// 
        /// <remarks>This feature is available only with the SQL Server 2005 Express Edition. 
        /// For more information on user instances, see Connecting to SQL Server Express User 
        /// Instances (ADO.NET) and "User Instances for Non-Administrators" in SQL Server Books Online.
        /// </remarks>
        /// </summary>
        public Boolean UserInstance
        {
            get
            {
                return this.SqlConnectionStringBuilder.UserInstance;
            }
            set
            {
                this.SqlConnectionStringBuilder.UserInstance = value;
            }
        }
        /// <summary>
        /// Gets or sets the name of the workstation connecting to SQL Server.
        /// </summary>
        public String WorkstationID
        {
            get
            {
                return this.SqlConnectionStringBuilder.WorkstationID;
            }
            set
            {
                this.SqlConnectionStringBuilder.WorkstationID = value;
            }
        }
        #endregion
        /// <summary>
        /// Manage MS SQL Boolean through the Enumerator Flags. Set only if needed. Not setted flags are marked as False Values.
        /// </summary>
        public SqlFlags BooleanFlags
        {
            get
            {
                return this._BooleanFlags;
            }
            set
            {
                var tmp = this.SqlConnectionStringBuilder;
                tmp.AsynchronousProcessing = value.HasFlag(SqlFlags.AsynchronousProcessing);
                tmp.ContextConnection = value.HasFlag(SqlFlags.ContextConnection);
                tmp.Encrypt = value.HasFlag(SqlFlags.Encrypt);
                tmp.Enlist = value.HasFlag(SqlFlags.Enlist);
                tmp.IntegratedSecurity = value.HasFlag(SqlFlags.IntegratedSecurity);
                tmp.MultipleActiveResultSets = value.HasFlag(SqlFlags.MultipleActiveResultSets);
                tmp.PersistSecurityInfo = value.HasFlag(SqlFlags.PersistSecurityInfo);
                tmp.Pooling = value.HasFlag(SqlFlags.Pooling);
                tmp.Replication = value.HasFlag(SqlFlags.Replication);
                tmp.TrustServerCertificate = value.HasFlag(SqlFlags.TrustServerCertificate);
                tmp.UserInstance = value.HasFlag(SqlFlags.UserInstance);
                this._BooleanFlags = value;
            }
        }
        private SqlFlags _BooleanFlags;
        /// <summary>
        /// Create new SQL Connection with integrated security
        /// </summary>
        /// <param name="server"></param>
        public SqlConnectionInfo(String server)
            : this(server, null, null)
        {
            this.IntegratedSecurity = true;
        }
        /// <summary>
        /// Create new MS Sql connection information based on raw authentication with server, user and password.
        /// </summary>
        /// <param name="server">Instance (Server) Name</param>
        /// <param name="user">User ID that should be used to establish SQL Connection</param>
        /// <param name="password">Sql Server Password</param>
        public SqlConnectionInfo(String server, String user, String password)
            : base(Databases.MSSQL, server, user, password)
        {
        }
        /// <summary>
        /// Create new MS Sql connection information based on Connection String Builder
        /// </summary>
        /// <param name="scsb">Connection String Builder that provide with Connection information.</param>
        public SqlConnectionInfo(System.Data.SqlClient.SqlConnectionStringBuilder scsb)
            : base(Databases.MSSQL, scsb)
        {
        }
        /// <summary>
        /// Create new Sql Connection String Builder
        /// </summary>
        /// <returns></returns>
        protected override System.Data.Common.DbConnectionStringBuilder GetConnectionStringbuilder()
        {
            this.ClientFactory = System.Data.SqlClient.SqlClientFactory.Instance;
            var result = this.ClientFactory.CreateConnectionStringBuilder() as System.Data.SqlClient.SqlConnectionStringBuilder;
            result.DataSource = this.Server;
            if (String.IsNullOrEmpty(base.UserName) == false)
                result.UserID = this.UserName;
            if (String.IsNullOrEmpty(base.Password) == false)
                result.Password = this.Password;

            return result;
        }
        /// <summary>
        /// Create new Db Parameter
        /// </summary>
        /// <param name="name">Parameter Name</param>
        /// <param name="value">Parameter Value</param>
        /// <param name="type">Use System.Data.SqlDbType for inserted parameter</param>
        /// <param name="isNullable">if true, empty object will be converted to DbNull.Value</param>
        /// <param name="Size">Object Size.</param>
        /// <returns>Return new DbParameter</returns>
        public override System.Data.Common.DbParameter CreateParameter(string name, object value, object type, bool isNullable, int Size = 0)
        {
            var param = this.ClientFactory.CreateParameter() as System.Data.SqlClient.SqlParameter;
            param.ParameterName = name;
            param.Value = (isNullable && value == null) ? DBNull.Value : value;
            param.Size = Size;
            if (type is System.Data.SqlDbType)
                param.SqlDbType = (System.Data.SqlDbType)type;
            else if (type is System.Data.DbType)
                param.DbType = (System.Data.DbType)type;
            else
                throw new ArgumentException("Could not recognize Db Type");
            param.IsNullable = isNullable;
            return param;
        }
        /// <summary>
        /// Create new Db Parameter. Autodetect parameter value type
        /// </summary>
        /// <param name="name">Parameter Name</param>
        /// <param name="value">Parameter Value</param>
        /// <param name="isNullable">if true, empty object will be converted to DbNull.Value</param>
        /// <param name="Size">Object Size.</param>
        /// <returns>Return new DbParameter</returns>
        public override System.Data.Common.DbParameter CreateParameter(string name, object value, bool isNullable, int Size = 0)
        {
            return this.CreateParameter(name, value, DbTypeConverter.ToDbType(value), isNullable, Size);
        }
    }
}
